//==============================================================================
//
//               Copyright (C) 2005  Dick van Oudheusden
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2005-02-28 19:21:48 $ $Revision: 1.3 $
//
//==============================================================================

#include <stdlib.h>

#include "ofc/DBigInt.h"

#include "DInc.h"
#include "DTest.h"


//-Wrappers--------------------------------------------------------------------

void DBigInt_test(void)
{
#ifdef HAVE_DBIGINT
  DBigInt *nr1    = [DBigInt alloc];
  DBigInt *nr2    = [DBigInt alloc];
  DBigInt *nr3    = [DBigInt alloc];
  DBigInt *nr4    = nil;
  DBigInt *nr5    = [DBigInt new];
  DText   *txt    = nil;
  DData   *data   = nil;
  char    parse[] = "0x781EF985A4457C AAF";
  char   *pntr    = parse;
  
  STARTTEST();

  [nr1 init];
  [nr2 init :-61231234];
  [nr3 init];
  [nr3 set :"12AA74532CEF902342EE004" : 16];
  
  nr4 = [nr3 copy];

  TEST([nr3 compare :nr4] == 0);

  TEST(![nr1 isNegative]);
  TEST( [nr2 isNegative]);
  TEST(![nr3 isNegative]);
  TEST(![nr4 isNegative]);
  
  TEST( [nr1 isZero]);
  TEST(![nr2 isZero]);
  TEST(![nr3 isZero]);
  TEST(![nr4 isZero]);
  
  [nr4 clear];
  
  TEST( [nr4 isZero]);
  
  [nr4 move :nr3];
  
  TEST([nr4 compare :nr3] == 0);
  
  TEST([nr1 get] == 0);
  TEST([nr2 get] == -61231234);
  

  txt = [nr4 get :16];
  
  TEST([txt icompare :"12AA74532CEF902342EE004"] == 0);
  
  [txt free];
  
  

  [nr1 set :"348967128475875903673405847858738562095023874" :10];
  [nr2 set :"-893458747924875230987023" :10];
  [nr3 set :"9812347571286413278947890034891750918" :10];
  [nr4 set :"-93497834987149871394791479817498748917132498147891234" :10];
  

  [nr5 move :nr1]; // nr5 = nr1
  
  [nr5 add :nr4];  // nr5 += nr4
  
  txt = [nr5 get :10];

  TEST([txt icompare :"-93497834638182742918915576144092901058393936052867360"] == 0);
  
  [txt free];
  
  
  [nr5 add :nr2 :nr3]; // nr5 = nr2 + nr3
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"9812347571285519820199965159660763895"] == 0);
  
  [txt free];
  
  
  [nr5 move :nr1];
  
  [nr5 sub :nr4]; // nr5 -= nr4
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"93497835336116999870667383490904596775871060242915108"] == 0);
  
  [txt free];
  
  
  [nr5 sub :nr2 :nr3]; // nr5 = nr2 - nr3
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"-9812347571287306737695814910122737941"] == 0);
  
  [txt free];

  
  [nr5 move :nr1];
  
  [nr5 mul :nr4]; // nr5 *= nr4
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"-32627670994176974242226664159590857146476853602471664014977231168389892430892214562875957985320516"] == 0);
  
  [txt free];

  
  [nr5 mul :nr2 :nr3]; // nr5 = nr2 * nr3
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"-8766927775245249212851418922963983503694579167296921806337114"] == 0);
  
  [txt free];

  
  [nr5 move :nr1];
  
  [nr5 div :nr2]; // nr5 /= nr2
  
  txt = [nr5 get :10];

  TEST([txt icompare :"-390580011988665577267"] == 0);
  
  [txt free];

  
  [nr5 div :nr4 :nr2]; // nr5 = nr4 / nr2
  
  txt = [nr5 get :10];

  TEST([txt icompare :"104647064236939406992607697862"] == 0);
  
  [txt free];

  
  [nr5 move :nr1];
  
  [nr5 mod :nr2]; // nr5 %= nr2
  
  txt = [nr5 get :10];

  TEST([txt icompare :"-530944931249498385782267"] == 0);
  
  [txt free];


  [nr5 mod :nr4 :nr2]; // nr5 = nr4 % nr2
  
  txt = [nr5 get :10];
  
  TEST([txt icompare :"-473352835180112121046408"] == 0);
  
  [txt free];

  
  [nr2 abs];
  
  txt = [nr2 get :10];
  
  TEST([txt icompare :"893458747924875230987023"] == 0);
  
  [txt free];
  
  
  [nr2 com];
  
  txt = [nr2 get :10];

  TEST([txt icompare :"-893458747924875230987024"] == 0);
  
  [txt free];
  

  [nr2 negate];
  
  txt = [nr2 get :10];
  
  TEST([txt icompare :"893458747924875230987024"] == 0);
  
  [txt free];
  

  [nr1 set :"1001011110111000010101000011001100101010100001101010101000101101011101010011101010010101" :2];
  [nr2 set :          "111110101111110111110101111010110010111110110011101010101111010101010101010101" :2];
  [nr3 set :                "111010101010110111000100000011000011000001010000001010000011100000100010" :2];
  [nr4 set :"1001010101001001101001010100101010101000101001010101010100101010101010101010101010101010" :2];
  
  [nr5 move :nr1];
  
  [nr5 and :nr4];  // nr5 &= nr4
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"1001010100001000000001000000001000101000100001000000000000101000001000000010101010000000"] == 0);
  
  [txt free];

  
  [nr5 and :nr2 :nr3]; // nr5 = nr2 & nr3
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"101010100010110101000000000010000010000001000000001010000001000000000000"] == 0);
  
  [txt free];
  
  
  [nr5 move :nr1];
  
  [nr5 or :nr4];  // nr5 |= nr4
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"1001011111111001111101010111101110101010101001111111111100101111111111111011101010111111"] == 0);
  
  [txt free];

  
  [nr5 or :nr2 :nr3]; // nr5 = nr2 | nr3
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"111110111111111111110111111110110011111111110011111010101111010111110101110111"] == 0);
  
  [txt free];
  
  
  [nr5 move :nr1];
  
  [nr5 xor :nr4];  // nr5 ^= nr4
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"1011110001111100010111100110000010001000111111111100000111110111111001000000111111"] == 0);
  
  [txt free];

  
  [nr5 xor :nr2 :nr3]; // nr5 = nr2 ^ nr3
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"111110010101011101000010111110110001111101110010111010100101010110110101110111"] == 0);
  
  [txt free];

  
  // Shifts
  [nr5 move :nr3];
  
  [nr5 lshift :7];
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"1110101010101101110001000000110000110000010100000010100000111000001000100000000"] == 0);
  
  [txt free];
  
  [nr5 lshift :nr3 :7];
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"1110101010101101110001000000110000110000010100000010100000111000001000100000000"] == 0);
  
  [txt free];


  
  [nr5 move :nr3];
  
  [nr5 rshift :7];
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"11101010101011011100010000001100001100000101000000101000001110000"] == 0);
  
  [txt free];
  
  [nr5 rshift :nr3 :7];
  
  txt = [nr5 get :2];
  
  TEST([txt icompare :"11101010101011011100010000001100001100000101000000101000001110000"] == 0);
  
  [txt free];


  // Conversion
 
  TEST([nr5 fromString :&pntr] == 0);
  
  TEST(*pntr == ' ');
  
  txt = [nr5 toText];
  
  TEST([txt icompare :"33811054243104124"] == 0);
  
  [txt free];
  
  // Import and export
  [nr1 set :"348967128475875903673405847858738562095023874" :10];
  [nr2 set :256];
  
  data = [nr1 toData]; // Export
  txt  = [nr1 get :16];
  
  TEST(data != nil);
  
  [nr3 mod :nr1 :nr2]; // Determine least significant byte
  
  TEST([data get :0] == (unsigned char) [nr3 get]);
  
  [nr2 set :[data data] :[data length] :NO]; // Import
  
  TEST([nr2 compare :nr1] == 0);
  
  [data free];
  [txt  free];
  
  [nr1 free];
  [nr2 free];
  [nr3 free];
  [nr4 free];
  [nr5 free];

  STOPTEST();
#endif
}

